﻿using System;
using System.Collections.Generic;
using System.Configuration;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using CarolLib.Extension;
using DCS.Business.Interface;
using DCS.Business.Manager;
using DCS.Business.Model;
using DCS.DataProvider;
using Microsoft.Practices.Unity;
using Microsoft.Practices.Unity.Configuration;

namespace DCS.BusinessObject
{
    public class Parser : IMessageParser
    {
        static log4net.ILog Logger = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
        static LDMMessageManager LDMmanager;
        static DCSFileManager DCSmanager;

        static readonly System.IFormatProvider culture = new System.Globalization.CultureInfo("en-US", true);
        static readonly Regex rgFirstLine = new Regex("[0-9A-Z]{3,7}/[0-9]{2}[A-Z]{3}.");
        static readonly Regex rgPDate = new Regex("[0-9]{2}[A-Z]{3}[0-9]{2}");
        static readonly Regex rgRegNo = new Regex(@"\.B[0-9]{3,5}\.");
        static readonly Regex rgLayout = new Regex(@"[0-9A-Z]{2,20}\.[0-9]{2}/[0-9]{2}");
        static readonly Regex rgLspHeader = new Regex(@"[0-9]{2}[A-Z]{3}[0-9]{2} [0-9]{4}");
        static readonly char[] dot = { '.' };
        static readonly char[] slash = { '/' };

        #region IMessageParser Members

        public void Init()
        {
            IUnityContainer myContainer = new UnityContainer();
            UnityConfigurationSection section
              = (UnityConfigurationSection)ConfigurationManager.GetSection("unity");
            section.Containers["Data"].Configure(myContainer);

            IDataProvider dp = myContainer.Resolve<IDataProvider>();

            LDMmanager = new LDMMessageManager(dp);
            DCSmanager = new DCSFileManager(dp);
        }

        public void DetectAndParse(int batchSize, string messageType)
        {
            List<DCSFile> files = new List<DCSFile>();

            try
            {
                files = DCSmanager.GetFilesToParse(batchSize, messageType);
            }
            catch(Exception e)
            {
                Logger.Error("Error in DCSmanager.GetFilesToParse", e);
            }

            if (files.Count == 0)
            {
                Logger.Debug("There is no new LDM files. ");
                System.Threading.Thread.Sleep(10000);
                return;
            }

            List<LDMMessage> results = new List<LDMMessage>();

            Logger.DebugFormat("Begain to parse {0} LDMMessages", files.Count);

            foreach (var item in files)
            {
                try
                {
                    results.AddRange(Parse(item));
                    item.Status = FileStatus.FinishParse;
                }
                catch (Exception e)
                {
                    Logger.Error(e);
                    item.Status = FileStatus.ParseError;
                }
            }

            try
            {
                LDMmanager.SaveEntities(results);
                Logger.DebugFormat("Parse {0} LDMMessages successful", files.Count(f => f.Status == FileStatus.FinishParse));
            }
            catch (Exception e)
            {
                Logger.Error(e);
                files.ForEach(f => f.Status = FileStatus.ParseError);
            }

            try
            {
                DCSmanager.UpdateDCSFilesStatus(files);
            }
            catch (Exception e)
            {
                Logger.Error("Error in UpdateDCSFilesStatus", e);
            }
        }

        private List<LDMMessage> Parse(DCSFile item)
        {
            List<LDMMessage> list = new List<LDMMessage>();
            LDMMessage model = null;
            LDMMessage model2 = null;

            using (FileStream fs = new FileStream(item.LocalPath + "\\" + item.LocalFileName, FileMode.Open, FileAccess.Read))
            {
                using (StreamReader reader = new StreamReader(fs, Encoding.UTF8))
                {
                    string text = string.Empty;
                    StringBuilder lsp = new StringBuilder();

                    while (!reader.EndOfStream)
                    {
                        text = reader.ReadLine();

                        #region Parse

                        #region LSP Part

                        if (text.EndsWith("DATE    TIME"))
                        {
                            model = new LDMMessage();
                            model.RefFileId = item.FileId;

                            text = reader.ReadLine();

                            #region SYM KMG MU5894/06SEP10  B5265   F8Y126         3/5/0    06SEP10 1950

                            string ptime = rgLspHeader.Match(text).Value;
                            model.PTime = DateTime.ParseExact(ptime, "ddMMMyy HHmm", culture, System.Globalization.DateTimeStyles.NoCurrentDateDefault);
                            model.DeptAirport = text.Substring(0, 3);

                            #endregion
                        }

                        #endregion

                        #region LDM Part

                        if (text == "LDM")
                        {
                            #region MU0517/07SEP10.B5475.C8Y162.02/07

                            text = reader.ReadLine();

                            if (rgFirstLine.IsMatch(text))
                            {
                                model.Carrier = text.Substring(0, 2);
                                model.FlightNo = text.Substring(2, text.IndexOf('/') - 2);
                                string pdate = rgPDate.Match(text).Value;
                                if (string.IsNullOrEmpty(pdate))//容错
                                {
                                    pdate = rgPDate.Match(item.LocalFileName).Value;
                                }
                                model.PDate = DateTime.ParseExact(pdate, "ddMMMyy", culture);
                                model.RegNo = rgRegNo.Match(text).Value.Replace(".", string.Empty);
                                string[] last = rgLayout.Match(text).Value.Split(dot);
                                model.Crew = last[1];
                                model.PaxLayout = last[0];

                                //add by lance 2011.04.06
                                model.LspContent = lsp.ToString();
                                lsp = null;
                            }

                            #endregion

                            text = reader.ReadLine();
                            if (text.StartsWith("-"))
                            {
                                FillMessageBody(model, reader, text);

                                list.Add(model);

                                text = reader.ReadLine();
                                if (text.StartsWith("-"))
                                {
                                    model2 = model.Clone() as LDMMessage;

                                    FillMessageBody(model2, reader, text);

                                    list.Add(model2);
                                    text = reader.ReadLine();

                                }

                                #region SI

                                text += reader.ReadToEnd();
                                list.ForEach(d => d.AdditionalInfo = text);

                                #endregion
                            }
                        }

                        #endregion

                        if (lsp != null)
                        {
                            lsp.AppendLine(text);
                        }

                        #endregion
                    }
                }
            }

            return list;
        }

        private void FillMessageBody(LDMMessage model, StreamReader reader, string text)
        {
            #region -PVG.104/0/0.0.T673.2/673

            model.ArrAirport = text.Substring(1, 3);
            string[] block = text.Substring(5).Split(dot);

            string[] ps = block[0].Split(slash);
            if (ps.Length<3 && text.EndsWith(".NIL"))
            {
                //NIL record.
                model.LoadInCompartment = string.Empty;
                return;
            }
            model.Adult = ps[0].TryToInt();
            model.Child = ps[1].TryToInt();
            model.Baby = ps[2].TryToInt();

            model.BagWeight = block[1].TryToInt();
            model.LoadTotal = block[2].Substring(1).TryToInt();

            int startLIC = text.IndexOf(block[2]) + block[2].Length + 1;
            if (startLIC < text.Length)
            {
                model.LoadInCompartment = text.Substring(text.IndexOf(block[2]) + block[2].Length + 1);
            }
            else
            {
                model.LoadInCompartment = string.Empty;
            }

            #endregion

            #region .PAX/2/102.PAD/0/0

            text = reader.ReadLine();
            if (!text.StartsWith(".PAX"))
            {
                model.LoadInCompartment += text;
                text = reader.ReadLine();
            }

            ps = text.Split(dot, StringSplitOptions.RemoveEmptyEntries);
            string[] paxs = ps[0].Replace("PAX", string.Empty).Split(slash, StringSplitOptions.RemoveEmptyEntries);
            string[] pads = ps[1].Replace("PAD", string.Empty).Split(slash, StringSplitOptions.RemoveEmptyEntries);

            if ((paxs.Length == 1)
                && (model.PaxLayout.Contains('Y'))
                && !(model.PaxLayout.Contains('C'))
                && !(model.PaxLayout.Contains('F')))
            {
                model.PaxF = 0;
                model.PaxC = 0;
                model.PaxY = paxs[0].TryToInt();
                model.PadF = 0;
                model.PadC = 0;
                model.PadY = pads[0].TryToInt();
            }
            else if ((paxs.Length == 2)
                && (model.PaxLayout.Contains('Y'))
                && (model.PaxLayout.Contains('C'))
                && !(model.PaxLayout.Contains('F')))
            {
                model.PaxF = 0;
                model.PaxC = paxs[0].TryToInt();
                model.PaxY = paxs[1].TryToInt();
                model.PadF = 0;
                model.PadC = pads[0].TryToInt();
                model.PadY = pads[1].TryToInt();
            }
            else if ((paxs.Length == 2)
                && (model.PaxLayout.Contains('Y'))
                && !(model.PaxLayout.Contains('C'))
                && (model.PaxLayout.Contains('F')))
            {
                model.PaxF = paxs[0].TryToInt();
                model.PaxC = 0;
                model.PaxY = paxs[1].TryToInt();
                model.PadF = pads[0].TryToInt();
                model.PadC = 0;
                model.PadY = pads[1].TryToInt();
            }
            else
            {
                model.PaxF = paxs[0].TryToInt();
                model.PaxC = paxs[1].TryToInt();
                model.PaxY = paxs[2].TryToInt();
                model.PadF = pads[0].TryToInt();
                model.PadC = pads[1].TryToInt();
                model.PadY = pads[2].TryToInt();
            }

            #endregion
        }

        #endregion
    }
}
